/**
 * @file    app_communication.c
 * @author  yhy
 * @brief   通信系统
 * @version 1.00
 * @date    2025-07-20
 *
 * @copyright Copyright (c) 2025
 *
 */
#include "app_communication.h"

#include "common_debug.h"
#include "common_util.h"
#include "drv_can.h"
#include "drv_gpio.h"

#include <stdio.h>
#include <string.h>

#define CAN_INSTANCE CAN_INSTANCE_CAN0_1

#pragma pack(1)

/**
 * @brief 通用结构体, 用于memcpy
 *
 */
typedef struct
{
    uint32_t can_id;
    union
    {
        uint8_t bytes[8];
    } can_data_u;
} hvs_generic_t;

#pragma pack()

/**
 * @brief CAN消息处理映射表
 *
 */
typedef struct
{
    uint32_t can_id;    /*!< CAN ID  */
    void    *data_ptr;  /*!< 数据指针 */
    size_t   data_size; /*!< 数据大小 */
} can_msg_handler_t;

static result_e app_communication_can_config(void);
static void     app_communication_can_recv_callback(uint32_t hw_instance, void *param);
static void app_communication_ready_can_send_msg_frame(msg_frame_t *msg_frame_list, uint8_t frame_count);
static result_e app_communication_can_push_queue(msg_queue_t *send_queue, msg_frame_t *msg_frame_list,
                                                 uint8_t frame_count);

hvs_fl_req1_t hvs_fl_req1 = {
    .can_id           = 0x111,
    .can_data_u.bytes = { 0 },
};

hvs_fl_req2_t hvs_fl_req2 = {
    .can_id           = 0x112,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts1_t hvs_fl_sts1 = {
    .can_id           = 0x151,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts2_t hvs_fl_sts2 = {
    .can_id           = 0x152,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts3_t hvs_fl_sts3 = {
    .can_id           = 0x153,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts4_t hvs_fl_sts4 = {
    .can_id           = 0x154,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts5_t hvs_fl_sts5 = {
    .can_id           = 0x155,
    .can_data_u.bytes = { 0 },
};

hvs_fl_sts6_t hvs_fl_sts6 = {
    .can_id           = 0x161,
    .can_data_u.bytes = { 0 },
};

/* CAN接收消息映射表 */
static const can_msg_handler_t CAN_RECV_HANDLER_LIST[] = {
    { 0x111, hvs_fl_req1.can_data_u.bytes, sizeof(hvs_fl_req1.can_data_u.bytes) },
    { 0x112, hvs_fl_req2.can_data_u.bytes, sizeof(hvs_fl_req2.can_data_u.bytes) },
    /* ...可拓展... */
};

/* CAN接收消息映射表数量  */
static const uint8_t CAN_RECV_HANDLER_COUNT =
    sizeof(CAN_RECV_HANDLER_LIST) / sizeof(CAN_RECV_HANDLER_LIST[0]);

/* 发送、接收消息队列 */
static msg_queue_t msg_send_queue;
static msg_frame_t msg_send_frame_buf[MASSAGE_QUEUE_BUFFER_MAXSIZE];
static msg_queue_t msg_recv_queue;
static msg_frame_t msg_recv_frame_buf[MASSAGE_QUEUE_BUFFER_MAXSIZE];

/* 传感器消息队列，存储获取的传感器数据 */
msg_queue_t sensor_msg_queue;
msg_frame_t sensor_msg_frame_buf[MASSAGE_QUEUE_BUFFER_MAXSIZE];

/**
 * @brief 初始化通信模块
 *
 */
void app_communication_init(void)
{
    /* 初始化CAN外设, 并拉低STB */
    result_e ret = app_communication_can_config();
    if (ret != RESULT_STATUS_OK) {
        LOG("app_communication_init: app_communication_can_config failed: %u\n", ret);
        return;
    }

    /* 初始化消息队列 */
    common_queue_init(&msg_send_queue, msg_send_frame_buf, MASSAGE_QUEUE_BUFFER_MAXSIZE);
    common_queue_init(&msg_recv_queue, msg_recv_frame_buf, MASSAGE_QUEUE_BUFFER_MAXSIZE);
    common_queue_init(&sensor_msg_queue, sensor_msg_frame_buf, MASSAGE_QUEUE_BUFFER_MAXSIZE);
}

/**
 * @brief 准备数据, 并将消息放入消息队列
 *
 */
void app_communication_can_prepare_data(void)
{
#ifdef SEAT_POSITION_DRIVER
    /* 准备消息帧 */
    msg_frame_t msg_frame_list[CAN_SEND_FRAME_TYPE_COUNT] = { 0 };
    app_communication_ready_can_send_msg_frame(msg_frame_list, CAN_SEND_FRAME_TYPE_COUNT);

    /* 消息入队列 */
    result_e ret =
        app_communication_can_push_queue(&msg_send_queue, msg_frame_list, CAN_SEND_FRAME_TYPE_COUNT);
    if (ret != RESULT_STATUS_OK) {
        LOG("app_communication_can_send: app_communication_can_push_queue failed: %u\n", ret);
    }
#endif
}

/**
 * @brief 从消息队列中取出1帧数据, 发送到CAN总线上
 *
 */
void app_communication_can_send(void)
{
    result_e        result    = RESULT_STATUS_OK;
    snf_can_frame_t can_frame = { 0 };

    if (!common_queue_is_empty(&msg_send_queue)) {
        msg_frame_t msg_frame = { 0 };
        common_queue_pop(&msg_send_queue, &msg_frame);

        can_frame.std_id = msg_frame.msg_id;
        can_frame.dlc    = msg_frame.data_len;
        memcpy(can_frame.data, msg_frame.data, msg_frame.data_len);

        result = snf_drv_can_transmit(CAN_INSTANCE, &can_frame);
        if (result != RESULT_STATUS_OK) {
            LOG("app_communication_can_send2bus: snf_drv_can_transmit failed: %u\n", result);
        }
    }
}

/**
 * @brief 接收CAN消息, 并赋值给hvs_req
 *
 */
void app_communication_can_recv_handle(void)
{
    if (common_queue_is_empty(&msg_recv_queue)) {
        return;
    }

    msg_frame_t msg_frame = { 0 };
    common_queue_pop(&msg_recv_queue, &msg_frame);

    /* 查找对应的处理器 */
    for (uint8_t i = 0; i < CAN_RECV_HANDLER_COUNT; ++i) {
        if (msg_frame.msg_id == CAN_RECV_HANDLER_LIST[i].can_id) {
            memcpy(CAN_RECV_HANDLER_LIST[i].data_ptr, msg_frame.data, CAN_RECV_HANDLER_LIST[i].data_size);
            return;
        }
    }
    LOG("app_communication_can_recv_handle: abnormal recv can_id: %u\n", msg_frame.msg_id);
}

/**
 * @brief 将CAN帧放入发送消息队列
 *
 * @param send_queue        发送消息队列
 * @param msg_frame_list    消息帧列表
 * @param frame_count       消息帧数量
 * @return result_e         入队结果, 成功返回RESULT_STATUS_OK, 失败返回其他
 */
static result_e app_communication_can_push_queue(msg_queue_t *send_queue, msg_frame_t *msg_frame_list,
                                                 uint8_t frame_count)
{
    for (uint8_t i = 0; i < frame_count; ++i) {
        if (common_queue_is_full(send_queue)) {
            return RESULT_STATUS_QUEUE_FULL;
        }

        common_queue_push(send_queue, msg_frame_list[i]);
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief 准备CAN发送消息帧
 *
 * @param msg_frame_list
 * @param frame_count
 */
static void app_communication_ready_can_send_msg_frame(msg_frame_t *msg_frame_list, uint8_t frame_count)
{
    hvs_generic_t *hvs_sts_list[] = {
        (hvs_generic_t *)&hvs_fl_sts1, (hvs_generic_t *)&hvs_fl_sts2, (hvs_generic_t *)&hvs_fl_sts3,
        (hvs_generic_t *)&hvs_fl_sts4, (hvs_generic_t *)&hvs_fl_sts5, (hvs_generic_t *)&hvs_fl_sts6,
    };

    for (uint8_t i = 0; i < frame_count && i < CAN_SEND_FRAME_TYPE_COUNT; ++i) {
        msg_frame_list[i].msg_id   = hvs_sts_list[i]->can_id;
        msg_frame_list[i].data_len = sizeof(hvs_sts_list[i]->can_data_u.bytes);
        memcpy(msg_frame_list[i].data, hvs_sts_list[i]->can_data_u.bytes,
               sizeof(hvs_sts_list[i]->can_data_u.bytes));
    }
}

/**
 * @brief CAN接收回调函数, 将接收到的CAN帧放入接收消息队列
 *
 * @param hw_instance   CAN实例, 可忽略
 * @param param         接收到的CAN帧
 */
static void app_communication_can_recv_callback(uint32_t hw_instance, void *param)
{
    /* 判断队列是否已经满了 */
    if (common_queue_is_full(&msg_recv_queue)) {
        LOG("app_communication_can_recv_callback: msg_recv_queue is full\n");
        return;
    }

    snf_can_frame_t *can_frame = (snf_can_frame_t *)param;

    /* 将CAN帧转换成消息帧 */
    msg_frame_t msg_frame = {
        .msg_id   = can_frame->std_id,
        .data_len = can_frame->dlc,
    };
    memcpy(msg_frame.data, can_frame->data, can_frame->dlc);

    /* 将消息帧放入接收消息队列 */
    if (msg_frame.msg_id >= SENSOR_BASE_ID && msg_frame.msg_id <= SENSOR_MAX_ID) {
        common_queue_push(&sensor_msg_queue, msg_frame);
    }
    else {
        common_queue_push(&msg_recv_queue, msg_frame);
    }
}

/**
 * @brief 配置CAN外设
 *
 * @return result_e 配置结果, 成功返回RESULT_STATUS_OK, 失败返回其他
 */
static result_e app_communication_can_config(void)
{
    snf_can_config_t can_config = {
        .instance          = CAN_INSTANCE,
        .fd_enable         = false,
        .filter            = { { 0x111, 0x000 }, { 0x112, 0x000 }, { 0x310, 0x00F } },
        .tx_callback       = NULL,
        .tx_callback_param = NULL,
        .rx_callback       = app_communication_can_recv_callback,
        .rx_callback_param = NULL,
    };

    result_e ret = snf_drv_can_init(&can_config);
    if (ret != RESULT_STATUS_OK) {
        LOG("app_communication_can_config: snf_drv_can_init failed: %u\n", ret);
        return ret;
    }

    /* 拉低STB, PE9 */
    snf_gpio_config_t gpio_config = {
        .pin_num    = GET_PIN_NUM(E, 9),
        .mode       = DRV_GPIO_PIN_MODE_OUTPUT,
        .init_level = DRV_GPIO_PIN_LEVEL_LOW,
    };
    ret = snf_drv_gpio_init(&gpio_config);
    if (ret != RESULT_STATUS_OK) {
        LOG("app_communication_can_config: snf_drv_gpio_init failed: %u\n", ret);
        return ret;
    }

    return RESULT_STATUS_OK;
}
